﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using TMPro;
using static ModsConfig;
using static UnityEditor.Progress;
using static UnityEngine.Rendering.DebugUI;

namespace Miao
{
    /// <summary>n
    /// Mod读取的核心类，这套框架将所有的数据以xml格式读取Def。
    /// </summary>
    public static class LoadedModManager
    {
        private static List<ModContentPack> runningMods = new List<ModContentPack>();
        public static List<ModContentPack> RunningMods => runningMods;

        private static Dictionary<Type, Mod> runningModClasses = new Dictionary<Type, Mod>();

        private static List<Def> patchedDefs = new List<Def>();

        public static bool IsInitialized = false;

        public static void DoPlayLoad(ModsConfigData activeModsHash)
        {
            if (IsInitialized)
            {
                ConfigRefresh(activeModsHash);
                ReBuildMod();
            }
            else
            {
                ConfigRefresh(activeModsHash);
                //载入mod数据
                ReBuildMod();
            }


        }

        public static void ReBuildMod()
        {
            Clear();
            LoadAllActiveMods();
            //置入Def
            AddAllDef();
            //对Def引用Def进行解析
            DirectXmlCrossRefLoader.ResolveAllWantedCrossReferencesParallelForEach(FailMode.LogErrors);
            IsInitialized = true;
        }


        public static void ConfigRefresh(ModsConfigData activeModsHashSet)
        {
            ModsConfig.LoadArchiveMod(activeModsHashSet);
        }

        private static void LoadAllActiveMods()
        {
            XmlInheritance.Clear();

            InitializeMods();
            LoadModContent();
            CreateModClasses();
            List<LoadableXmlAsset> xmls = null;
            xmls = LoadModXML();
            Dictionary<XmlNode, LoadableXmlAsset> assetlookup = new Dictionary<XmlNode, LoadableXmlAsset>();

            XmlDocument xmlDocument = CombineIntoUnifiedXML(xmls, assetlookup);
            //TKeySystem调用忽略，疑似改键
            InitPatches();

            ErrorCheckPatches();
            ApplyPatches(xmlDocument);
            ///解析完毕
            ParseAndProcessXML(xmlDocument, assetlookup);
        }

        /// <summary>
        /// 获取Mod成Mod包
        /// </summary>
        private static void InitializeMods()
        {

            for (int i = 0; i < ModsConfig.ActiveModsInLoadOrder.Count; i++)
            {
                ModMetaData modMetaData = ModsConfig.ActiveModsInLoadOrder[i];
                ModContentPack item = new ModContentPack(modMetaData.RootDir, modMetaData.PackageId, i, modMetaData.FolderName, modMetaData.official);
                runningMods.Add(item);
            }
        }


        /// <summary>
        /// 载入存档内容(dll)和资源
        /// </summary>
        private static void LoadModContent()
        {
            for (int i = 0; i < RunningMods.Count; i++)
            {
                ModContentPack modContentPack = RunningMods[i];
                modContentPack.ReloadContent();

            }
        }
        /// <summary>
        /// 读取继承自Mod的配置类型
        /// </summary>
        private static void CreateModClasses()
        {

            foreach (Type type in typeof(Mod).InstantiableDescendantsAndSelf())
            {
                //读取assemblies内包含的Mod定义。
                ModContentPack modContentPack = RunningMods.Where((ModContentPack modpack) => modpack.assemblies.loadedAssemblies.Contains(type.Assembly)).FirstOrDefault();
            }
        }
        /// <summary>
        /// 载入ModXml先实现这个
        /// </summary>
        /// <returns></returns>
        private static List<LoadableXmlAsset> LoadModXML()
        {
            List<LoadableXmlAsset> list = new List<LoadableXmlAsset>();

            for (int i = 0; i < runningMods.Count; i++)
            {
                ModContentPack modContentPack = runningMods[i];
                list.AddRange(modContentPack.LoadDefs());

            }
            return list;
        }
        /// <summary>
        /// 将零散分散的XML合并成统一的XML
        /// </summary>
        /// <param name="xmls"></param>
        /// <param name="assetlookup"></param>
        /// <returns></returns>
        private static XmlDocument CombineIntoUnifiedXML(List<LoadableXmlAsset> xmls, Dictionary<XmlNode, LoadableXmlAsset> assetlookup)
        {
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.AppendChild(xmlDocument.CreateElement("Defs"));

            foreach (LoadableXmlAsset xml in xmls)
            {
                if (xml.xmlDoc == null || xml.xmlDoc.DocumentElement == null)
                {
                    Log.Error(string.Format("{0}: unknown parse failure", xml.fullFolderPath + "/" + xml.name));
                    continue;
                }
                if (xml.xmlDoc.DocumentElement.Name != "Defs")
                {
                    Log.Error(string.Format("{0}: root element named {1}; should be named Defs", xml.fullFolderPath + "/" + xml.name, xml.xmlDoc.DocumentElement.Name));
                }
                foreach (XmlNode childNode in xml.xmlDoc.DocumentElement.ChildNodes)
                {
                    XmlNode xmlNode = xmlDocument.ImportNode(childNode, deep: true);
                    assetlookup[xmlNode] = xml;
                    xmlDocument.DocumentElement.AppendChild(xmlNode);
                }
            }
            return xmlDocument;
        }
        private static void InitPatches()
        {
            foreach (ModContentPack runningMod in runningMods)
            {
                runningMod.LoadPatches();
            }
        }
        /// <summary>
        /// 汇报Patch可能存在的问题
        /// </summary>
        private static void ErrorCheckPatches()
        {
            foreach (ModContentPack runningMod in runningMods)
            {
                foreach (PatchOperation patch in runningMod.patches)
                {
                    try
                    {
                        foreach (string item in patch.ConfigErrors())
                        {
                            Log.Error(string.Concat("Config error in ", runningMod.Name, " patch ", patch, ": ", item));
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Error(string.Concat("Exception in ConfigErrors() of ", runningMod.Name, " patch ", patch, ": ", ex));
                    }
                }
            }
        }

        private static void ApplyPatches(XmlDocument xmlDoc)
        {
            foreach (PatchOperation item in runningMods.SelectMany((ModContentPack rm) => rm.patches))
            {
                item.Apply(xmlDoc);
            }
        }
        /// <summary>
        /// 分析和处理XML
        /// </summary>
        /// <param name="xmlDoc"></param>
        /// <param name="assetlookup"></param>
        private static void ParseAndProcessXML(XmlDocument xmlDoc, Dictionary<XmlNode, LoadableXmlAsset> assetlookup)
        {
             XmlNodeList childNodes = xmlDoc.DocumentElement.ChildNodes;
            List<XmlNode> list = new List<XmlNode>();

            foreach (XmlNode item in childNodes)
            {
                list.Add(item);
            }

            for (int i = 0; i < list.Count; i++)
            {
                if (list[i].NodeType == XmlNodeType.Element)
                {

                    assetlookup.TryGetValue(list[i], out LoadableXmlAsset loadableXmlAsset);
                    XmlInheritance.TryRegister(list[i], loadableXmlAsset?.mod);
                }
            }

            //XML继承解析
            XmlInheritance.Resolve();

            for (int i = 0; i < list.Count; i++)
            {
                assetlookup.TryGetValue(list[i], out LoadableXmlAsset loadableXmlAsset);

                Def def = DirectXmlLoader.DefFromNode(list[i]);

                if (def != null)
                {
                    ModContentPack modContentPack = loadableXmlAsset?.mod;

                    if (modContentPack != null)
                    {
                        modContentPack.AddDef(def);
                    }
                    else
                    {
                        patchedDefs.Add(def);
                    }

                }
            }

        }
        //GenGeneric.InvokeStaticMethodOnGenericType(typeof(DefDatabase<>), item, "AddAllInMods");

        private static void AddAllDef()
        {
            foreach (Type item in typeof(Def).AllSubclasses())
            {
                MiaoGeneric.InvokeStaticMethodOnGenericType(typeof(DefDatabase<>), item, "AddAllInMods");
            }
        }
        private static void RemoveAllDef()
        {
            foreach (Type item in typeof(Def).AllSubclasses())
            {
                MiaoGeneric.InvokeStaticMethodOnGenericType(typeof(DefDatabase<>), item, "Clear");
            }
        }


        public static void Clear()
        {
            ModContentTexture.ClearDestroy();
            ModContentSound.ClearDestroy();

            runningModClasses.Clear();
            patchedDefs.Clear();

            //AllContentTexture.ClearDestroy();
            //将图片数据存储在统一的字典中加快检索。
            //foreach (ModContentPack runningMod in runningMods)
            //{
            //    try
            //    {
            //        runningMod.ClearDestroy();
            //    }
            //    catch (Exception ex)
            //    {
            //        Log.Error("Error in mod.ClearDestroy(): " + ex);
            //    }
            //}
            runningMods.Clear();

            RemoveAllDef();


        }




        private static void ClearCachedPatches()
        {

        }
    }
}
